#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <string.h>

int sm2_sign_verify() {
    EVP_PKEY *pkey = NULL;
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL);
    if (!pctx) return -1;

    // 生成 SM2 密钥对
    if (EVP_PKEY_keygen_init(pctx) <= 0) goto err;
    if (EVP_PKEY_keygen(pctx, &pkey) <= 0) goto err;
    EVP_PKEY_CTX_free(pctx);

    const char *msg = "20231318fsl";
    size_t msg_len = strlen(msg);

    // 签名
    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
    if (!mctx) goto err;

    // 使用 SM3 作为摘要算法
    EVP_PKEY_CTX *sigctx;
    if (EVP_DigestSignInit(mctx, &sigctx, EVP_sm3(), NULL, pkey) <= 0) goto err;
    
    // 设置用户 ID 为 "20231318"
    const char *id = "20231318";
    if (EVP_PKEY_CTX_set1_id(sigctx, id, strlen(id)) <= 0) goto err;

    size_t siglen;
    if (EVP_DigestSign(mctx, NULL, &siglen, (unsigned char*)msg, msg_len) <= 0) goto err;
    unsigned char *sig = OPENSSL_malloc(siglen);
    if (!sig) goto err;
    if (EVP_DigestSign(mctx, sig, &siglen, (unsigned char*)msg, msg_len) <= 0) {
        OPENSSL_free(sig);
        goto err;
    }
    EVP_MD_CTX_free(mctx);

    // 验签
    mctx = EVP_MD_CTX_new();
    if (!mctx) {
        OPENSSL_free(sig);
        goto err;
    }

    if (EVP_DigestVerifyInit(mctx, &sigctx, EVP_sm3(), NULL, pkey) <= 0) {
        EVP_MD_CTX_free(mctx);
        OPENSSL_free(sig);
        goto err;
    }
    if (EVP_PKEY_CTX_set1_id(sigctx, id, strlen(id)) <= 0) {
        EVP_MD_CTX_free(mctx);
        OPENSSL_free(sig);
        goto err;
    }
    
    int verified = EVP_DigestVerify(mctx, sig, siglen, (unsigned char*)msg, msg_len);
    printf("SM2 signature %s\n", verified ? "OK" : "FAILED");

    EVP_MD_CTX_free(mctx);
    OPENSSL_free(sig);
    EVP_PKEY_free(pkey);
    return 0;

err:
    if (pctx) EVP_PKEY_CTX_free(pctx);
    if (mctx) EVP_MD_CTX_free(mctx);
    if (sig) OPENSSL_free(sig);
    if (pkey) EVP_PKEY_free(pkey);
    return -1;
}

int main() {
    if (sm2_sign_verify() == 0) {
        printf("SM2 签名验证成功\n");
    } else {
        printf("SM2 签名验证失败\n");
        return 1;
    }
    return 0;
}





